import {  decimalArrayToHexString } from '../utils/utils.js'
import BleSDK from './BleSDK.js';

const RETRY_COUNT = 3;

class CommandQueue {
	#queue;
	#isProcessing;
	#isPause;
	#commandHandleMap = new Map();

	static instance;

	failQueue;

	constructor() {
		this.#queue = [];
		this.#isProcessing = false;
		this.#isPause = false;
		this.failQueue = [];
	}

	static getInstance() {
		if (!CommandQueue.instance) {
			CommandQueue.instance = new CommandQueue();
		}
		return CommandQueue.instance;
	}

	getQueueCount() {
		return this.#queue.length + this.failQueue.length;
	}

	enqueue(command, callback) {
		if (!(command instanceof Uint8Array)) {
			command = new Uint8Array(command)
		}
		const obj = {
			command,
			failCount: 0,
		};
		this.#queue.push(obj);
		if (callback && typeof callback === "function" && command instanceof Uint8Array) {
			const head = command[0] === 0xab ? command[11] : command[0];
			if (!this.#commandHandleMap[head]) {
				this.#commandHandleMap[head] = new WeakMap();
			}
			this.#commandHandleMap[head][callback] = (value) => {
				delete this.#commandHandleMap[head][callback];
				callback(value);
			};
		}

		if (!this.#isProcessing) {
			this.processQueue();
		}
	}

	runHandle(head, value) {
		if (typeof head !== "number" && typeof head !== "string") throw new Error("first param must be number or string");
		if (this.#commandHandleMap[head]) {
			for (const key in this.#commandHandleMap[head]) {
				if (typeof this.#commandHandleMap[head][key] === "function") {
					this.#commandHandleMap[head][key](value);
				}
			}
		}
	}

	insetQueue(command) {
		if (command instanceof Array) {
			const objs = command.map((item) => ({
				command: item,
				failCount: 0,
			}));
			this.#queue.unshift(...objs);
		} else {
			const obj = {
				command,
				failCount: 0,
			};
			this.#queue.unshift(obj);
		}

		if (!this.#isProcessing) {
			this.processQueue();
		}
	}

	processQueue() {
		try {
			// LogCat.d("指令队列", this.#queue);
			if (this.#isPause || this.#queue.length === 0) {
				this.#isProcessing = false;
				// LogCat.d("指令队列为空或暂停，停止执行指令");
				return;
			}
			this.#isProcessing = true;
			const curCmd = this.#queue.shift();
			console.log("当前执行的指令：💫", curCmd);
			BleSDK.send(curCmd.command)
				.then((r) => {
					console.log("指令写入成功：🍔", curCmd);
					// LogCat.d("指令写入成功🍔", {
					// 	command: decimalArrayToHexString(curCmd.command),
					// 	failCount: curCmd.failCount,
					// });
					setTimeout(() => this.processQueue(), 200);
				})
				.catch((e) => {
					console.log("指令写入失败：☠", curCmd);
					// LogCat.d("指令写入失败☠", {
					// 	command: decimalArrayToHexString(curCmd.command),
					// 	failCount: curCmd.failCount,
					// });
					curCmd.failCount += 1;
					if (curCmd.failCount < RETRY_COUNT) {
						// 指令写入失败，重新入队
						this.#queue.push(curCmd);
					} else {
						// 指令写入失败超过3次，不再入队
						// LogCat.d(`指令写入失败超过${RETRY_COUNT}次，不再入队，推入失败队列☠`, {
						// 	command: decimalArrayToHexString(curCmd.command),
						// 	failCount: curCmd.failCount,
						// });
						this.failQueue.push(curCmd);
					}
					setTimeout(() => this.processQueue(), 200);
				});
		} catch (error) {
			console.log("最外层执行失败", error);
		}
	}

	clearQueue() {
		this.#queue = [];
		this.#isProcessing = false;
	}

	pauseQueue() {
		this.#isPause = true;
		// LogCat.d("暂停指令队列");
	}

	resumeQueue() {
		this.#isPause = false;
		if (!this.#isProcessing) {
			// LogCat.d("恢复指令队列", this.#queue);
			this.processQueue();
		}
	}

	retryFailCommand() {
		if (this.failQueue.length === 0) {
			// LogCat.d("重试指令队列为空");
			return;
		}
		this.#isProcessing = true;
		const curCmd = this.failQueue.shift();
		console.log("当前重试的指令：💫", curCmd);
		BleSDK.send(curCmd.command)
			.then((r) => {
				console.log("指令重试成功：🍔", curCmd);
				// LogCat.d("指令重试成功🍔", {
				// 	command: decimalArrayToHexString(curCmd.command),
				// 	failCount: curCmd.failCount,
				// });
				setTimeout(() => this.processQueue(), 200);
			})
			.catch((e) => {
				console.log("指令重试失败：☠", curCmd);
				// LogCat.d("指令重试失败☠", {
				// 	command: decimalArrayToHexString(curCmd.command),
				// 	failCount: curCmd.failCount,
				// });
				curCmd.failCount += 1;
				if (curCmd.failCount < RETRY_COUNT) {
					// 指令写入失败，重新入队
					this.failQueue.push(curCmd);
				} else {
					// 指令写入失败超过3次，不再入队
					// LogCat.d(`指令重试失败超过${RETRY_COUNT}次，不再入队，推入失败队列☠`, {
					// 	command: decimalArrayToHexString(curCmd.command),
					// 	failCount: curCmd.failCount,
					// });
				}
			});
	}
}

const instance = CommandQueue.getInstance();

export { instance as CommandQueue };
